#include "GraphicManager.h"

//Initializate the graphic manager
void cGraphicManager::Init()
{
  //Get the handler
  mHandle = GetStdHandle(STD_OUTPUT_HANDLE);

  //Initializate the backbuffer
  memset(macBackBuffer, ' ', kuiConsoleArea);

  //Initializate the color backbuffer
  memset(macColorBuffer, 0x0F, kuiConsoleArea);

  //Hide the cursor
  ShowCursor(false);
}

//Write a character into BackBuffer
void cGraphicManager::WriteChar(unsigned int luiX, unsigned int luiY, char lChar)
{
  //Calculate the position
  unsigned luiIndex = luiX + luiY * kuiConsoleDimX;

  //Put the char and the color to the buffers
  macBackBuffer[luiIndex] = lChar;
  macColorBuffer[luiIndex] = mcCurrentColour;
}


//Write a string into BackBuffer 
void cGraphicManager::WriteChars(unsigned int luiX, unsigned int luiY, char *lacStr, unsigned int luiLen)
{
  //Calculate the position
  unsigned luiIndex = luiX + luiY * kuiConsoleDimX;
  
  //Test that we don't go out of the buffer
  assert(luiIndex + luiLen < kuiConsoleArea);
  
  //Write characters into the buffers
  memcpy(&(macBackBuffer[luiIndex]), lacStr, luiLen);
  memset(&(macColorBuffer[luiIndex]), mcCurrentColour, luiLen);
}

//Write a string into BackBuffer
void cGraphicManager::WriteChars(unsigned int luiX, unsigned int luiY, char *lacStr)
{
  WriteChars(luiX, luiY, lacStr, strlen(lacStr));
}


//Set the foreground color
void cGraphicManager::SetForegroundColor(eColor leFore)
{
  unsigned char lcBackColor = (unsigned char) (mcCurrentColour & 0xF0);
  unsigned char lcForeColor = (unsigned char) leFore;
 
  mcCurrentColour = (lcForeColor|lcBackColor);
}


//Set the background color
void cGraphicManager::SetBackgroundColor(eColor leBack)
{
  unsigned char lcForeColor = (unsigned char) leBack << 4;
  unsigned char lcBackColor = (unsigned char) (mcCurrentColour & 0x0F);
 
  mcCurrentColour = (lcForeColor|lcBackColor);
}


//Set the color 
void cGraphicManager::SetColor(eColor leFore, eColor leBack)
{
  unsigned char lcForeColor = (unsigned char) leFore;
  unsigned char lcBackColor = (unsigned char) leBack;
  lcBackColor <<= 4;

  mcCurrentColour = (lcForeColor|lcBackColor);
}

//Paint the backbuffer into the screen
void cGraphicManager::SwapBuffers()
{
  //Initialize the coordinates
  COORD lCoord = {0,0};

  //Set the position
  SetConsoleCursorPosition(mHandle, lCoord);

  //Lock the console
  LockWindowUpdate(GetConsoleWindow());

  //Prepare the vars
  unsigned luiStart = 0;
  unsigned char lcColor = macColorBuffer[0];

  //For each character in the buffer
  for(unsigned luiIndex = 1; luiIndex < kuiConsoleArea; ++luiIndex)
  {
    //If the color has been changed
    if (macColorBuffer[luiIndex] != lcColor)
    {
      //Set the color
      SetConsoleTextAttribute(mHandle, (WORD)lcColor);

      //Print the characters
      DWORD liCount;
      int liCharacterCount = luiIndex - luiStart;
      WriteConsole(mHandle, &(macBackBuffer[luiStart]), liCharacterCount,
                   &liCount, NULL);

      //Update information
      luiStart = luiIndex;
      lcColor = macColorBuffer[luiIndex];
    }
  }

  //Set the color
  SetConsoleTextAttribute(mHandle, (WORD)lcColor);

  //Print the last chunk
  DWORD liCount;
  int liCharacterCount = kuiConsoleArea - luiStart;
  WriteConsole(mHandle, &(macBackBuffer[luiStart]),
               liCharacterCount, &liCount, NULL);

  //Set the position
  SetConsoleCursorPosition(mHandle, lCoord);

  //Unlock the console
  LockWindowUpdate(NULL);
}

//Clear the buffers
void cGraphicManager::ClearBuffer()
{
  memset(macBackBuffer, ' ', kuiConsoleArea);
  memset(macColorBuffer, mcCurrentColour, kuiConsoleArea);
}

//Show the cursor
void cGraphicManager::ShowCursor(bool lbShow)
{
  CONSOLE_CURSOR_INFO lCursor;
  if (GetConsoleCursorInfo(mHandle, &lCursor))
  {
    lCursor.bVisible = lbShow;
    SetConsoleCursorInfo(mHandle, &lCursor);
  }
}

//Deinitializate the Graphic Manager
void cGraphicManager::Deinit()
{
  //Put the screen into original colors
  SetColor(eWhite, eBlack);

  //Clear the screen
  ClearBuffer();

  //Show the cursor
  ShowCursor(true);
}